#include <windows.h>
#include <commctrl.h> // 包含Common Controls库的头文件
#include <wininet.h>  // 包含WinInet库的头文件
#include <tchar.h>
#include <shlobj.h> // 包含文件对话框相关的头文件
#include <shlwapi.h>
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "shell32.lib") // 添加shell32.lib以支持SHGetFolderPath
 
// 定义按钮和进度条的ID
#define ID_BUTTON 1
#define ID_EDIT_URL 2
#define ID_PROGRESSBAR 3
#define ID_STATUS_LABEL_TOTAL 4
#define ID_STATUS_LABEL_SPEED 5
#define ID_STATUS_LABEL_REMAINING 6
 
// 定义 ThreadParams 结构体
struct ThreadParams {
        HWND hWnd;
        const TCHAR* url;
        const TCHAR* filePath;
        volatile bool* isDownloading;
        LARGE_INTEGER startTime; // 下载开始时间
        LARGE_INTEGER frequency; // 性能计数器频率
};
 
// 全局变量
HWND hwndProgressBar = NULL;
HWND hwndStatusLabelTotal = NULL;
HWND hwndStatusLabelSpeed = NULL;
HWND hwndStatusLabelRemaining = NULL;
HWND hwndEditUrl = NULL;
HANDLE hDownloadThread = NULL;
DWORD downloadThreadId = 0;
volatile bool isDownloading = false;
 
// 线程函数声明
DWORD WINAPI DownloadThread(LPVOID lpParam);
 
// 窗口过程函数声明
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
        const wchar_t* CLASS_NAME = L"Sample Window Class";
 
        // 初始化Common Controls库
        INITCOMMONCONTROLSEX icex;
        icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
        icex.dwICC = ICC_BAR_CLASSES; // 初始化进度条控件
        InitCommonControlsEx(&icex);
 
        // 注册窗口类
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WndProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wc.lpszClassName = CLASS_NAME;
 
        if (!RegisterClassEx(&wc)) {
                MessageBox(NULL, L"Window Registration Failed!", L"Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                return 0;
        }
 
        // 创建窗口
        HWND hwnd = CreateWindowEx(
                0,                              // 扩展样式
                CLASS_NAME,                     // 窗口类名
                L"Learn to Program Windows",    // 窗口标题
                WS_OVERLAPPEDWINDOW,            // 窗口样式
                CW_USEDEFAULT, CW_USEDEFAULT,   // 窗口位置
                544, 375,                       // 窗口大小
                NULL,                           // 父窗口
                NULL,                           // 菜单
                hInstance,                      // 实例句柄
                NULL                            // 附加应用数据
                );
 
        if (hwnd == NULL) {
                MessageBox(NULL, L"Window Creation Failed!", L"Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                return 0;
        }
 
        // 创建编辑框
        hwndEditUrl = CreateWindowEx(
                WS_EX_CLIENTEDGE,               // 扩展样式
                L"EDIT",                         // 控件类名
                L"",                           // 初始文本为空
                WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, // 样式
                10,                             // x位置
                10,                             // y位置
                300,                            // 宽度
                20,                             // 高度
                hwnd,                           // 父窗口句柄
                (HMENU)ID_EDIT_URL,             // 控件ID
                hInstance,                      // 实例句柄
                NULL                            // 附加应用数据
                );
 
        if (hwndEditUrl == NULL) {
                MessageBox(NULL, L"Edit Box Creation Failed!", L"Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                return 0;
        }
 
        // 创建按钮
        HWND hwndButton = CreateWindowEx(
                0,                              // 扩展样式
                L"BUTTON",                      // 控件类名
                L"Start Download",              // 按钮文本
                WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // 样式
                320,                            // x位置
                10,                             // y位置
                100,                            // 宽度
                30,                             // 高度
                hwnd,                           // 父窗口句柄
                (HMENU)ID_BUTTON,               // 控件ID
                hInstance,                      // 实例句柄
                NULL                            // 附加应用数据
                );
 
        if (hwndButton == NULL) {
                MessageBox(NULL, L"Button Creation Failed!", L"Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                return 0;
        }
 
        // 创建进度条
        hwndProgressBar = CreateWindowEx(
                0,                              // 扩展样式
                PROGRESS_CLASS,                 // 控件类名
                NULL,                           // 进度条没有文本
                WS_VISIBLE | WS_CHILD | PBS_SMOOTH, // 样式，添加 PBS_SMOOTH
                10,                             // x位置
                50,                             // y位置
                520,                            // 宽度
                20,                             // 高度
                hwnd,                           // 父窗口句柄
                (HMENU)ID_PROGRESSBAR,          // 控件ID
                hInstance,                      // 实例句柄
                NULL                            // 附加应用数据
                );
 
        if (hwndProgressBar == NULL) {
                MessageBox(NULL, L"Progress Bar Creation Failed!", L"Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                return 0;
        }
 
        // 创建总进度标签
        hwndStatusLabelTotal = CreateWindowEx(
                0,                              // 扩展样式
                L"STATIC",                     // 控件类名
                L"",                           // 初始文本为空
                WS_VISIBLE | WS_CHILD,          // 样式
                10,                             // x位置
                80,                             // y位置
                520,                            // 宽度
                20,                             // 高度
                hwnd,                           // 父窗口句柄
                (HMENU)ID_STATUS_LABEL_TOTAL,   // 控件ID
                hInstance,                      // 实例句柄
                NULL                            // 附加应用数据
                );
 
        if (hwndStatusLabelTotal == NULL) {
                MessageBox(NULL, L"Status Label Total Creation Failed!", L"Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                return 0;
        }
 
        // 创建速度标签
        hwndStatusLabelSpeed = CreateWindowEx(
                0,                              // 扩展样式
                L"STATIC",                     // 控件类名
                L"",                           // 初始文本为空
                WS_VISIBLE | WS_CHILD,          // 样式
                10,                             // x位置
                110,                            // y位置
                520,                            // 宽度
                20,                             // 高度
                hwnd,                           // 父窗口句柄
                (HMENU)ID_STATUS_LABEL_SPEED,   // 控件ID
                hInstance,                      // 实例句柄
                NULL                            // 附加应用数据
                );
 
        if (hwndStatusLabelSpeed == NULL) {
                MessageBox(NULL, L"Status Label Speed Creation Failed!", L"Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                return 0;
        }
 
        // 创建剩余时间标签
        hwndStatusLabelRemaining = CreateWindowEx(
                0,                              // 扩展样式
                L"STATIC",                     // 控件类名
                L"",                           // 初始文本为空
                WS_VISIBLE | WS_CHILD,          // 样式
                10,                             // x位置
                140,                            // y位置
                520,                            // 宽度
                20,                             // 高度
                hwnd,                           // 父窗口句柄
                (HMENU)ID_STATUS_LABEL_REMAINING, // 控件ID
                hInstance,                      // 实例句柄
                NULL                            // 附加应用数据
                );
 
        if (hwndStatusLabelRemaining == NULL) {
                MessageBox(NULL, L"Status Label Remaining Creation Failed!", L"Error!",
                        MB_ICONEXCLAMATION | MB_OK);
                return 0;
        }
 
        // 设置进度条的范围和初始位置
        SendMessage(hwndProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); // 设置范围为0到100
        SendMessage(hwndProgressBar, PBM_SETPOS, 0, 0);                  // 设置当前位置为0
 
        ShowWindow(hwnd, nCmdShow);
 
        // 消息循环
        MSG msg = { 0 };
        while (GetMessage(&msg, NULL, 0, 0)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
        }
 
        return (int)msg.wParam;
}
 
// 定义 StartDownload 函数
void StartDownload(HWND hWnd, const TCHAR* url, const TCHAR* filePath, volatile bool& isDownloading) {
        ThreadParams* params = new ThreadParams{ hWnd, url, filePath, &isDownloading };
        QueryPerformanceFrequency(¶ms->frequency); // 初始化性能计数器频率
        LARGE_INTEGER startCounter;
        QueryPerformanceCounter(&startCounter); // 记录开始时间
        params->startTime.QuadPart = startCounter.QuadPart;
        hDownloadThread = CreateThread(NULL, 0, DownloadThread, params, 0, &downloadThreadId);
        if (hDownloadThread == NULL) {
                MessageBox(NULL, L"CreateThread failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK);
                isDownloading = false;
                delete params; // 释放内存
        }
}
 
// 线程函数定义
DWORD WINAPI DownloadThread(LPVOID lpParam) {
        ThreadParams* params = static_cast<ThreadParams*>(lpParam);
        HWND hWnd = params->hWnd;
        const TCHAR* url = params->url;
        const TCHAR* filePath = params->filePath;
        volatile bool* isDownloading = params->isDownloading;
        LARGE_INTEGER frequency = params->frequency;
 
        HINTERNET hInternet = InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
        if (hInternet == NULL) {
                MessageBox(hWnd, L"InternetOpen failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK);
                *isDownloading = false;
                delete params;
                return 1;
        }
 
        HINTERNET hUrl = InternetOpenUrl(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
        if (hUrl == NULL) {
                InternetCloseHandle(hInternet);
                MessageBox(hWnd, L"InternetOpenUrl failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK);
                *isDownloading = false;
                delete params;
                return 1;
        }
 
        DWORD fileSize = 0;
        DWORD size = sizeof(fileSize);
 
        // 获取文件大小
        if (!HttpQueryInfo(hUrl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &fileSize, &size, 0)) {
                fileSize = 0; // 如果无法获取文件大小，则设为0
        }
 
        HANDLE hFile = CreateFile(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
                InternetCloseHandle(hUrl);
                InternetCloseHandle(hInternet);
                MessageBox(hWnd, L"CreateFile failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK);
                *isDownloading = false;
                delete params;
                return 1;
        }
 
        DWORD bytesRead = 0;
        DWORD totalBytesRead = 0;
        char buffer[4096];
        LARGE_INTEGER previousTime;
        LARGE_INTEGER currentTime;
        double elapsedTime;
        double downloadSpeed;
        double remainingTime;
        TCHAR statusTextTotal[256];
        TCHAR statusTextSpeed[256];
        TCHAR statusTextRemaining[256];
 
        QueryPerformanceCounter(&previousTime); // 初始化上一次时间
 
        while (InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
                WriteFile(hFile, buffer, bytesRead, &bytesRead, NULL); // bytesRead 用于接收实际写入的字节数
                totalBytesRead += bytesRead; // 累加实际写入的字节数
 
                if (fileSize > 0) {
                        int progress = (int)((static_cast<double>(totalBytesRead) / fileSize) * 100); // 计算进度百分比
                        PostMessage(hWnd, WM_USER + 1, progress, 0); // 更新进度条位置
 
                        QueryPerformanceCounter(¤tTime);
                        elapsedTime = (currentTime.QuadPart - previousTime.QuadPart) / (double)frequency.QuadPart; // 计算经过的时间（秒）
                        if (elapsedTime > 0.001) { // 避免除零错误
                                downloadSpeed = bytesRead / elapsedTime; // 计算瞬时下载速度（字节/秒）
                                remainingTime = (fileSize - totalBytesRead) / downloadSpeed; // 计算剩余时间（秒）
 
                                // 将字节转换为MB
                                double totalBytesReadMB = totalBytesRead / 1024.0 / 1024.0;
                                double fileSizeMB = fileSize / 1024.0 / 1024.0;
                                double downloadSpeedMBps = downloadSpeed / 1024.0 / 1024.0;
 
                                _stprintf_s(statusTextTotal, 256, _T("%.2fMB/%.2fMB"), totalBytesReadMB, fileSizeMB);
                                _stprintf_s(statusTextSpeed, 256, _T("速度 %.2fMB/s"), downloadSpeedMBps);
                                _stprintf_s(statusTextRemaining, 256, _T("剩余 %.2f秒"), remainingTime);
 
                                PostMessage(hWnd, WM_USER + 2, 0, (LPARAM)statusTextTotal); // 发送总进度文本
                                PostMessage(hWnd, WM_USER + 3, 0, (LPARAM)statusTextSpeed); // 发送速度文本
                                PostMessage(hWnd, WM_USER + 4, 0, (LPARAM)statusTextRemaining); // 发送剩余时间文本
 
                                previousTime = currentTime; // 更新上一次时间
                        }
                }
                else {
                        // 如果无法获取文件大小，直接显示已读取的字节数
                        double totalBytesReadMB = totalBytesRead / 1024.0 / 1024.0;
                        _stprintf_s(statusTextTotal, 256, _T("%.2fMB"), totalBytesReadMB);
                        PostMessage(hWnd, WM_USER + 2, 0, (LPARAM)statusTextTotal); // 发送总进度文本
                }
        }
 
        CloseHandle(hFile);
        InternetCloseHandle(hUrl);
        InternetCloseHandle(hInternet);
 
        *isDownloading = false;
        PostMessage(hWnd, WM_USER + 1, 100, 0);
        delete params;
        return 0;
}
 
// 示例按钮点击事件处理函数
void OnDownloadButtonClick(HWND hWnd) {
        TCHAR url[1024];
        GetWindowText(hwndEditUrl, url, 1024); // 从编辑框中获取URL
 
        if (_tcslen(url) == 0) {
                MessageBox(hWnd, L"Please enter a valid URL.", L"Information", MB_OK | MB_ICONINFORMATION);
                return;
        }
 
        if (isDownloading) {
                MessageBox(hWnd, L"Download is already in progress.", L"Information", MB_OK | MB_ICONINFORMATION);
                return;
        }
 
        // 使用文件对话框选择保存位置
        OPENFILENAME ofn;
        TCHAR szFile[MAX_PATH] = { 0 };
 
        ZeroMemory(&ofn, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hWnd;
        ofn.lpstrFilter = L"All Files (*.*)\0*.*\0";
        ofn.lpstrFile = szFile;
        ofn.nMaxFile = MAX_PATH;
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
 
        // 解析URL以获取文件名
        LPCTSTR pszFileName = PathFindFileName(url);
        if (pszFileName && _tcslen(pszFileName) > 0) {
                lstrcpy(szFile, pszFileName);
        }
        else {
                lstrcpy(szFile, _T("downloaded_file")); // 默认文件名
        }
 
        // 提取文件扩展名
        LPCTSTR pszFileExt = PathFindExtension(pszFileName);
        if (pszFileExt && _tcslen(pszFileExt) > 0) {
                // 如果URL中包含扩展名，则直接使用
                lstrcat(szFile, pszFileExt);
        }
        else {
                // 如果URL中不包含扩展名，则尝试从HTTP响应头中获取
                HINTERNET hInternet = InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
                if (hInternet != NULL) {
                        HINTERNET hUrl = InternetOpenUrl(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
                        if (hUrl != NULL) {
                                TCHAR contentType[256];
                                DWORD contentTypeSize = sizeof(contentType);
                                if (HttpQueryInfo(hUrl, HTTP_QUERY_CONTENT_DISPOSITION | HTTP_QUERY_FLAG_REQUEST_HEADERS, contentType, &contentTypeSize, 0)) {
                                        // 解析Content-Disposition头以获取文件名
                                        TCHAR* pszFilename = PathFindFileName(contentType);
                                        if (pszFilename && _tcslen(pszFilename) > 0) {
                                                LPCTSTR pszFilenameExt = PathFindExtension(pszFilename);
                                                if (pszFilenameExt && _tcslen(pszFilenameExt) > 0) {
                                                        lstrcpy(szFile, pszFilename);
                                                }
                                        }
                                }
                                InternetCloseHandle(hUrl);
                        }
                        InternetCloseHandle(hInternet);
                }
        }
 
 
        // 获取桌面路径作为默认路径
        TCHAR desktopPath[MAX_PATH];
        SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, desktopPath);
        PathCombine(szFile, desktopPath, szFile);
 
 
 
 
        if (GetSaveFileName(&ofn)) {
                isDownloading = true;
                StartDownload(hWnd, url, szFile, isDownloading);
        }
}
 
 
// 窗口过程函数定义
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
        switch (msg) {
        case WM_COMMAND:
                if (LOWORD(wParam) == ID_BUTTON) {
                        OnDownloadButtonClick(hwnd);
                }
                break;
        case WM_USER + 1:
                SendMessage(hwndProgressBar, PBM_SETPOS, wParam, 0); // 更新进度条位置
                break;
        case WM_USER + 2:
                SetWindowText(hwndStatusLabelTotal, (LPCTSTR)lParam); // 更新总进度标签文本
                break;
        case WM_USER + 3:
                SetWindowText(hwndStatusLabelSpeed, (LPCTSTR)lParam); // 更新速度标签文本
                break;
        case WM_USER + 4:
                SetWindowText(hwndStatusLabelRemaining, (LPCTSTR)lParam); // 更新剩余时间标签文本
                break;
        case WM_DESTROY:
                if (hDownloadThread != NULL) {
                        WaitForSingleObject(hDownloadThread, INFINITE);
                        CloseHandle(hDownloadThread);
                }
                PostQuitMessage(0);
                break;
        default:
                return DefWindowProc(hwnd, msg, wParam, lParam);
        }
        return 0;
}